﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using OpenCost.Common.Attributes;
using OpenCost.Common.Interfaces.Output;

namespace OpenCost
{
    public static class PluginProvider
    {
        private static List<OutputHost> outputPlugins;

        public static List<OutputHost> LoadedOutputPlugins
        {
            get
            {
                if (outputPlugins == null)
                {
                    ReloadPlugins();
                }
                return outputPlugins;
            }
        }
        public static void ReloadPlugins()
        {
            if (outputPlugins == null)
            {
                outputPlugins = new List<OutputHost>();
            }
            else
            {
                outputPlugins.Clear();
            }

            List<Assembly> plugInAssemblies = LoadPlugInAssemblies();
            List<IOutput> plugins = GetPlugIns(plugInAssemblies);
            foreach (IOutput outputPlugin in plugins)
            {
                outputPlugins.Add(new OutputHost(outputPlugin));
            }
        }

        private static List<Assembly> LoadPlugInAssemblies()
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(Environment.CurrentDirectory, "Plugins"));
            FileInfo[] files = directoryInfo.GetFiles("*.dll");

            List<Assembly> plugInAssemblyList = new List<Assembly>();


            foreach (FileInfo file in files)
            {
                plugInAssemblyList.Add(Assembly.LoadFile(file.FullName));
            }

            return plugInAssemblyList;
        }

        static List<IOutput> GetPlugIns(List<Assembly> assemblies)
        {
            List<Type> availableTypes = new List<Type>();

            foreach (Assembly currentAssembly in assemblies)
            {
                try
                {
                    availableTypes.AddRange(currentAssembly.GetTypes());
                }
                catch (Exception)
                {

                }

            }

            //get a list of objects that implement the IOutput interface AND have the plugin attribute
            List<Type> pluginList = availableTypes.FindAll(delegate(Type t)
                                                               {
                                                                   List<Type> interfaceTypes =
                                                                       new List<Type>(t.GetInterfaces());
                                                                   object[] arr =
                                                                       t.GetCustomAttributes(typeof(PlugInAttribute),
                                                                                             true);
                                                                   return arr.Length != 0 &&
                                                                          interfaceTypes.Contains(typeof(IOutput));
                                                               });
            return pluginList.ConvertAll(t => Activator.CreateInstance(t) as IOutput);
        }

        public static void ToggleActivation(string pluginName)
        {
            foreach (OutputHost plugin in outputPlugins)
            {
                if (plugin.PluginTitle == pluginName)
                {
                    plugin.isActive = !plugin.isActive;
                }
            }
        }

    }
}
